package com.lion.seaman.orm;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

@SuppressWarnings("unchecked")
public abstract class BaseRunSQL {
    protected EntityManagerFactory emf;

    public abstract void setEntityManagerFactory(EntityManagerFactory emf);

    /**
     * 开始事务
     */
    public EntityManager txBegin() {
        EntityManager newEm = this.emf.createEntityManager();
        EntityTransaction newTx = newEm.getTransaction();
        newTx.begin();
        return newEm;
    }

    /**
     * 提交事务
     */
    public void txCommit(EntityManager entityManager) {
        entityManager.getTransaction().commit();
    }

    /**
     * 回滚事务
     */
    public void txRollBack(EntityManager entityManager) {
        if (entityManager != null) {
            entityManager.getTransaction().rollback();
        }
    }

    /**
     * 执行sql语句，指定返回类型
     *
     * @param sql
     * @param clazz
     * @return
     */
    public <T> List<T> executeSQL(String sql, Class<T> clazz) {
        return executeSQL(sql, null, clazz);
    }

    /**
     * 执行sql语句，指定返回类型
     *
     * @param sql
     * @param clazz
     * @return
     */
    public <T> List<T> executeSQL(String sql, Map<String, Object> parameters,
                                  Class<T> clazz) {
        EntityManager newEm = this.emf.createEntityManager();
        Query query = newEm.createNativeQuery(sql, clazz);
        if (parameters != null) {
            for (Entry<String, Object> p : parameters.entrySet()) {
                query.setParameter(p.getKey(), p.getValue());
            }
        }
        List<T> result = query.getResultList();
        return result;
    }

    /**
     * 执行sql语句
     *
     * @param sql
     * @return
     */
    public List<?> executeSQL(String sql) {
        EntityManager newEm = this.emf.createEntityManager();
        Query query = newEm.createNativeQuery(sql);
        List<?> list = executeQuery(query);
        return list;
    }

    /**
     * 执行查询,占位符(:name)
     *
     * @param sql
     * @param parameters
     * @return
     */
    public List<?> executeSQL(String sql, Map<String, Object> parameters) {
        EntityManager newEm = this.emf.createEntityManager();
        Query query = newEm.createNativeQuery(sql);
        if (parameters != null) {
            for (Entry<String, Object> p : parameters.entrySet()) {
                query.setParameter(p.getKey(), p.getValue());
            }
        }
        List<?> list = executeQuery(query);
        return list;
    }

    /**
     * 执行复合查询
     *
     * @param query
     * @return
     */
    public List<?> executeSQL(CriteriaQuery<?> query) {
        EntityManager newEm = this.emf.createEntityManager();
        List<?> list = executeQuery(newEm.createQuery(query));
        return list;
    }

    public Object executeSQLSingleResult(String sql) {
        EntityManager newEm = this.emf.createEntityManager();
        return newEm.createNativeQuery(sql).getSingleResult();
    }


    /**
     * 执行查询
     *
     * @param query
     * @return
     */
    public List<?> executeQuery(Query query) {
        return query.getResultList();
    }

    /**
     * Return an instance of CriteriaBuilder for the creation of CriteriaQuery
     * objects.
     *
     * @return
     */
    public CriteriaBuilder getCriteriaBuilder() {
        EntityManager newEm = this.emf.createEntityManager();
        return newEm.getCriteriaBuilder();
    }

    /**
     * 执行sql，带事务
     *
     * @param sql
     * @return
     */
    public int executeUpdate(String sql) {
        EntityManager newEm = this.emf.createEntityManager();
        EntityTransaction newTx = newEm.getTransaction();
        newTx.begin();
        int count = newEm.createNativeQuery(sql).executeUpdate();
        newTx.commit();
        return count;
    }

    /**
     * 执行sql，不带事务
     *
     * @param sql
     * @return
     */
    public int executeUpdateWithoutTx(EntityManager entityManager, String sql) {
        int count = entityManager.createNativeQuery(sql).executeUpdate();
        return count;
    }
}
